package com.wjz.log.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.wjz.log.annotation.WebLog;
import com.wjz.log.entity.WebLogEntity;
import com.wjz.log.handler.WebLogHandler;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author wjz
 * @date 2021/5/31 16:22
 */

@Slf4j
@Aspect
@Component
public class WebLogAspect {

    private ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();
    private ThreadLocal<WebLogEntity> webLogEntityThreadLocal = new ThreadLocal<>();
    private ThreadLocal<Boolean> isPersistentThreadLocal = new ThreadLocal<>();

    @Autowired
    private WebLogHandler webLogHandler;

    @Pointcut("@annotation(com.wjz.log.annotation.WebLog)")
    public void start() {
    }

    @Before("start()")
    public void before(JoinPoint joinPoint) {
        log.info("前置通知===》");
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        WebLogEntity webLogEntity = new WebLogEntity();
        //获取方法输入的参数
        Object[] args = joinPoint.getArgs();
        List<Object> paramList = new ArrayList<>();
        for (Object arg : args) {
            paramList.add(arg);
        }
        String jsonParam = JSON.toJSONString(paramList, SerializerFeature.WriteNullListAsEmpty);
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        WebLog webLog = methodSignature.getMethod().getAnnotation(WebLog.class);
        webLogEntity.setRequestParam(jsonParam)
                .setOperateClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName())
                .setOperateDesc(webLog.value())
                .setBrowserInfo(request.getHeader("User-Agent"))
                .setRequestIP(request.getRemoteAddr())
                .setHttpMethod(request.getMethod())
                .setRequestURL(request.getRequestURI());
        startTimeThreadLocal.set(System.currentTimeMillis());
        webLogEntityThreadLocal.set(webLogEntity);
        isPersistentThreadLocal.set(webLog.persistent());
    }

    @AfterReturning(pointcut = "start()", returning = "object")
    public void afterReturning(Object object) {
        log.info("后置通知===》");
        try {
            WebLogEntity webLogEntity = webLogEntityThreadLocal.get();
            webLogEntity.setConsumeTime(System.currentTimeMillis() - startTimeThreadLocal.get())
                    .setOperateTime(new Date())
                    .setResponseResult(JSON.toJSONString(object));
            webLogHandler.persistentLog(webLogEntity, isPersistentThreadLocal.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
        webLogEntityThreadLocal.remove();
        startTimeThreadLocal.remove();
        isPersistentThreadLocal.remove();
    }

    @AfterThrowing(pointcut = "start()", throwing = "throwable")
    public void afterThrowing(Throwable throwable) {
        log.error("错误==》", throwable);
        WebLogEntity webLogEntity = webLogEntityThreadLocal.get();
        webLogEntity.setConsumeTime(System.currentTimeMillis() - startTimeThreadLocal.get())
                .setExceptionMsg(throwable.getMessage())
                .setOperateTime(new Date());
        try {
            webLogHandler.persistentLog(webLogEntity, true);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            webLogEntityThreadLocal.remove();
            startTimeThreadLocal.remove();
            isPersistentThreadLocal.remove();
        }
    }
}
